﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Excel = Microsoft.Office.Interop.Excel;

namespace BHA
{
    public class ItemSAP
    {
        public const string SAP_REGEX = @"^\s*((\d{5,9})[_-]?(\d*))\.?(\d*)\s*$";
        public const string UNIT_REGEX = @"ea|ft|m|kit|pair|set";
        public const string QUAN_REGEX = @"(\d+\.*\d*)(" + UNIT_REGEX + @")?";

        #region STATIC
        public static bool IsExtSAP(string Input)
        {
            if (string.IsNullOrWhiteSpace(Input)) return false;
            return Regex.IsMatch(Input, SAP_REGEX);
        }

        public static string GetExtSAP(string Input)
        {
            if (string.IsNullOrWhiteSpace(Input)) return null;
            //http://msdn.microsoft.com/en-us/library/system.text.regularexpressions.regex%28v=vs.110%29.aspx
            //http://msdn.microsoft.com/en-us/library/az24scfc%28v=vs.110%29.aspx
            return Regex.Match(Input, SAP_REGEX).Groups[0].Value;
        }

        public static string GetOrgSAP(string extendedSAP)
        {
            if (string.IsNullOrWhiteSpace(extendedSAP)) return null;
            return Regex.Match(extendedSAP, SAP_REGEX).Groups[2].Value;
        }

        public static string GetModSAP(string extendedSAP)
        {
            if (string.IsNullOrWhiteSpace(extendedSAP)) return null;
            return Regex.Match(extendedSAP, SAP_REGEX).Groups[1].Value;
        }

        public static string GetModRev(string extendedSAP)
        {
            if (string.IsNullOrWhiteSpace(extendedSAP)) return null;
            return Regex.Match(extendedSAP, SAP_REGEX).Groups[3].Value;
        }

        public static string GetExtRev(string extendedSAP)
        {
            if (string.IsNullOrWhiteSpace(extendedSAP)) return null;
            return Regex.Match(extendedSAP, SAP_REGEX).Groups[4].Value;
        }
        #endregion

        public string Serial { get; set; }
        /// <summary>
        /// Ex : 123456789.1 or 123456789_1.1 or 123456789-1.1
        /// </summary>
        public string NoSAP { get; set; }
        public string NoOrgSAP
        {
            get { return GetOrgSAP(NoSAP).Trim(); }
        }
        public string DescriptionSAP { get; set; }
        public string DescriptionUSE { get; set; }
        public double PriceSAP { get; set; }
        public double PriceBDPOC { get; set; }

        /// <summary>
        /// Formula for Quantity. Eg : "{Perf. Length}/6.905ea"
        /// </summary>
        public string QuanFormula { get; set; }
        public string Unit { get; set; }
        public double Quantity { get; set; }

        public List<ItemSAP> Items { get; set; }
        public Dictionary<int, List<ItemSAP>> BackupItems { get; set; }

        public ItemSAP()
        {
            Serial = "Unknown";
            NoSAP = "Unknown";
            DescriptionSAP = "Unknown";
            DescriptionUSE = "Unknown";
            PriceSAP = 0.000;
            PriceBDPOC = 0.000;
            Unit = "Unknown";
            Quantity = 0;
            QuanFormula = "Unknown";
            Items = new List<ItemSAP>();
        }

        public ItemSAP CloneQuanFormula(string VarCode)
        {
            if (VarCode == null) return null;
            // Trich 1 Var trong QuanFormula
            // Duyet qua cac Var trong FormulaVar neu trung voi Var trong QuanFormula
            // Neu co dang thi tinh ra quantity voi unit tuong ung

            // Parse QuanFormula
            // Trich cac Var trong FormulaVar dua vao list
            string[] varsections = Regex.Split(VarCode, @",");
            Dictionary<string, double> vardict = new Dictionary<string, double>();
            foreach (string varsection in varsections)
            {
                Match match = Regex.Match(varsection, @"\{(.+)\}(.*)$");
                double quan = 0;
                try
                {
                    if (!string.IsNullOrWhiteSpace(match.Groups[2].Value))
                        quan = Convert.ToDouble(match.Groups[2].Value);
                }
                catch (Exception e) { }

                vardict.Add(match.Groups[1].Value, quan);
            }   // vardict keep Key = "BackUp", Value = 0.5 ..etc..

            ItemSAP ret = null;
            if (Regex.IsMatch(this.QuanFormula, @"\{(.+)\}(" + UNIT_REGEX + ")"))
            {   //{EDA}ea 
                Match m = Regex.Match(this.QuanFormula, @"\{(.+)\}(" + UNIT_REGEX + ")");
                string sVar = m.Groups[1].Value;
                string sUnit = m.Groups[2].Value;
                ret = this.Clone(vardict[sVar]); ret.Unit = sUnit;
                //return ret; // Can use : return this.Clone(quan.ToString() + sUnit);
            }
            else if (Regex.IsMatch(this.QuanFormula, @"\{(.+)\}/([0-9\.]+)(" + UNIT_REGEX + ")"))
            {   //{Interval}/6.915ea 
                Match m = Regex.Match(this.QuanFormula, @"\{(.+)\}/([0-9\.]+)(" + UNIT_REGEX + ")");
                string sVar = m.Groups[1].Value;
                double k = 1; try { k = Convert.ToDouble(m.Groups[2].Value); }
                catch (Exception e) { }
                string sUnit = m.Groups[3].Value;
                double quan = Math.Truncate(vardict[sVar] / k) + 1;
                ret = this.Clone(quan); ret.Unit = sUnit;
                //return ret; // Can use : return this.Clone(quan.ToString() + sUnit);
            }
            else if (Regex.IsMatch(this.QuanFormula, @"\{(.+)\}/\{(.+)\}/([0-9\.]+)-([0-9\.]+)(" + UNIT_REGEX + ")"))
            {   //{Interval}/{Gun per Run}/6.915-1ea 
                Match m = Regex.Match(this.QuanFormula, @"\{(.+)\}/\{(.+)\}/([0-9\.]+)-([0-9\.]+)(" + UNIT_REGEX + ")");
                string sVar1 = m.Groups[1].Value;
                string sVar2 = m.Groups[2].Value;
                double k = 1; try { k = Convert.ToDouble(m.Groups[3].Value); }
                catch (Exception e) { }
                double b = 1; try { b = Convert.ToDouble(m.Groups[4].Value); }
                catch (Exception e) { }
                string sUnit = m.Groups[5].Value;
                double res = vardict[sVar1] / vardict[sVar2] / k - b;
                double quan = 0;
                if (res >= 0) quan = Math.Truncate(res) + 1; // >= : equal for safety reason, eg : 6 gun should bring 1 skirt + stinger
                ret = this.Clone(quan); ret.Unit = sUnit;
                //return ret; // Can use : return this.Clone(quan.ToString() + sUnit);
            }
            else if (Regex.IsMatch(this.QuanFormula, QUAN_REGEX))
            {   //5.9ea 
                ret = this.Clone(QuanFormula);
            }

            // Include BackUp
            foreach (string varcode in vardict.Keys)
            {
                if (Regex.IsMatch(varcode, PerfPlan.BACKUP_REGEX, RegexOptions.IgnoreCase))
                {
                    double quan = ret.Quantity * (1 + vardict[varcode]);
                    if (quan == Math.Round(quan)) ret.Quantity = quan; // No need to Round if not decimal number.
                    else ret.Quantity = Math.Truncate(quan) + 1; // Round Up, eg : if 1.5ea then take 2ea | if 150.5ft then take 151ft
                    break;
                }
            }

            return ret;
        }

        /// <summary>
        /// Clone new ItemSAP but Items still same object in heap. Ex : if 
        /// </summary>
        /// <param name="quantity"></param>
        /// <returns></returns>
        public ItemSAP Clone(string quantity)
        {   // Clone all Property but not Items (Sub Item)
            ItemSAP item = new ItemSAP();
            item.Serial = this.Serial;
            item.NoSAP = this.NoSAP;
            item.DescriptionSAP = this.DescriptionSAP;
            item.DescriptionUSE = this.DescriptionUSE;
            item.PriceSAP = this.PriceSAP;
            item.PriceBDPOC = this.PriceBDPOC;
            item.TrySetQuantity(quantity);
            item.Items = this.Items;
            return item;
        }

        public ItemSAP Clone(double quantity)
        {   // Clone all Property but not Items (Sub Item)
            ItemSAP item = new ItemSAP();
            item.Serial = this.Serial;
            item.NoSAP = this.NoSAP;
            item.DescriptionSAP = this.DescriptionSAP;
            item.DescriptionUSE = this.DescriptionUSE;
            item.PriceSAP = this.PriceSAP;
            item.PriceBDPOC = this.PriceBDPOC;
            item.Unit = this.Unit;
            item.Quantity = quantity;
            item.Items = this.Items;
            return item;
        }

        public List<ItemSAP> GetAllSubItems()
        {
            return null;
        }

        public bool TryAddQuantity(string Input)
        {
            try
            {
                //http://msdn.microsoft.com/en-us/library/az24scfc%28v=vs.110%29.aspx
                string input = Input.Replace(" ", "");
                Match match = Regex.Match(input, QUAN_REGEX);
                double quan = Convert.ToDouble(match.Groups[1].Value);
                string unit = match.Groups[2].Value;
                if (Unit == "Unknown") { Unit = unit; Quantity += quan; }
                else if (unit == Unit) Quantity += quan;
                else
                {
                    if (unit == "m" & Unit == "ft") Quantity += quan * 3.2808399;
                    else
                    {
                        System.Windows.Forms.MessageBox.Show(string.Format(
                            "Item SAP = {0}, DESC = {1}\r\nNOT support Unit below :\r\n  {2} (current unit : {3})",
                            NoSAP, DescriptionUSE, unit, Unit), "Add Quantity Fail"); return false;
                    }
                }
                return true;
            }
            catch (Exception e)
            {
                System.Windows.Forms.MessageBox.Show("Cannot Add Quantity from below String :\r\n  " + Input, "Add Quantity Fail");
                return false;
            }
        }

        /// <summary>
        /// Set Quantity base on Formula
        /// </summary>
        /// <param name="Input">Must be : "{Perf. Length}=300m, {EDA}=3ea"</param>
        /// <returns></returns>
        public bool TrySetQuanFormula(string Input)
        {
            return false;
            //{Perf. Length}/6.915ea
            //{Perf. Length}/6.915/{Gun Per Run}-1ea
            //{Perf. Length}/6.915/{Gun Per Run}-1ea
            //{EDA}ea

        }

        public bool TrySetQuantity(string Input)
        {
            try
            {
                //http://msdn.microsoft.com/en-us/library/az24scfc%28v=vs.110%29.aspx
                string input = Input.Replace(" ", "");
                Match match = Regex.Match(input, QUAN_REGEX);
                Quantity = Convert.ToDouble(match.Groups[1].Value);
                Unit = match.Groups[2].Value;
                return true;
            }
            catch (Exception e)
            {
                System.Windows.Forms.MessageBox.Show(string.Format(
                     "Item SAP = {0}, DESC = {1}\r\nCAN'T Set Quantity from below string :\r\n  {2}",
                        NoSAP, DescriptionUSE, Input), "Set Quantity Fail");
                return false;
            }
        }

        /// <summary>
        /// Cell to Fill Quanity with Unit
        /// </summary>
        /// <param name="cell"></param>
        public void FillQuantity(Excel.Range cell)
        {
            cell.Value = this.Quantity;
            cell.NumberFormat = "General"; //string.Format("General \"{0}\"", this.Unit);
            cell.Font.Color = System.Drawing.Color.Blue;
        }
    }

    class ItemSAPCollection
    {
        public List<ItemSAP> Items { get; set; }

        public ItemSAPCollection()
        {
            Items = new List<ItemSAP>();
        }


        /// <summary>
        /// Add ItemSAP to Collection, default Sum Quantity if Duplicate Sap No.
        /// </summary>
        /// <param name="item"></param>
        /// <param name="SumQuan"></param>
        public void Add(ItemSAP item, bool SumQuan = true)
        {
            if (!SumQuan) this.Items.Add(item);
            else
            {
                bool found = false;
                foreach (ItemSAP citem in this.Items)
                {
                    if (citem.NoSAP == item.NoSAP)
                    { citem.Quantity += item.Quantity; found = true; }
                }
                if (!found) this.Items.Add(item);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="list"></param>
        /// <param name="SumQuan"></param>
        public void AddRange(List<ItemSAP> list, bool SumQuan = true)
        {
            foreach (ItemSAP item in list)
            {
                this.Add(item, SumQuan);
            }
        }

        public List<ItemSAP> ItemsBySAP(string NoSAP)
        {
            List<ItemSAP> list = new List<ItemSAP>();
            foreach (ItemSAP item in Items)
            {
                if (item.NoSAP == NoSAP) list.Add(item);
            }
            return list;
        }
    }
}
